package com.example.demomail.util;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.*;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

/** 日期工具 所属公司: 华信联创技术工程有限公司 版本: 1.0 创建人: 徐延 创建时间: 2019-04-13 10:32 */
public class DateUtil {

    public static final String DATEFORMAT_YMD = "yyyyMMdd";
    public static final String DATEFORMAT_Y = "yyyy";
    public static final String DATEFORMART_YMDH = "yyyyMMddHH";
    public static final String DATEFORMART_HM = "yyyyMMddHHmm";
    public static final String DATEFORMART_HMS = "yyyyMMddHHmmss";
    public static final String DATEFORMART_DEFAULT = "yyyy-MM-dd HH:mm:ss";
    public static final String DATEFORMART_DEFAULT2 = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DATEFORMARTDEFAULT = "yyyyMMdd HH:mm:ss";
    public static final String DATEFORMART_YMD = "yyyy-MM-dd";
    public static final String DATEFORMART_DEF = "yyyy-MM-dd HH";
    public static final String DATEFORMART_DEF1 = "yyyy-MM-dd+HH";
    public static final String WEB_FORMATOR_YMDHM = "yyyy-MM-dd HH:mm";
    public static final String WEB_FORMATOR_MD = "MM-dd";
    public static final String WEB_FORMATOR_ym = "yyyy-MM-dd";
    public static final String WEB_FORMATOR_ym1 = "yyyy-MM-dd+";
    public static final String WEB_FORMATOR_YM2 = "yyyy-MM";
    public static final String WEB_FORMATOR_YM3 = "yyyyMM";
    public static final String WEB_FORMATOR_YMDs = "yyyy-MM-dd";
    public static final String WEB_FORMATOR_yms = "yyyy-MM-dd+HH:mm:ss";
    public static final String WEB_FORMATOR_ymdh = "yyyy-MM-dd+HH";
    public static final String WEB_FORMATOR_ymd = "yyyy-MM-dd ";
    public static final String WEB_FORMATOR_ymd2 = "yyyy_MM_dd";
    public static final String WEB_FORMATOR_ymds = "yyyy-MM-dd";
    public static final String WEB_FORMATOR_YMD = "yyyy年MM月dd日";
    public static final String WEB_FORMATOR_YM = "yyyy年MM月";
    public static final String WEB_FORMATOR_YMDHMS = "yyyy-MM-dd HH:mm:ss";
    public static final String WEB_FORMATOR_YMDH = "yyyy-MM-dd HH";
    public static final String WEB_FORMATOR_YMDH2 = "yyyy-MM-dd HH时";
    public static final String WEB_FORMATOR_YMDH3 = "yyyy/MM/dd HH:mm";
    public static final String WEB_FORMATOR_HM = "HH:mm";

    /**
     * Date对象转LocalDate对象
     *
     * @param date
     * @return java.time.LocalDate
     * @author 徐延
     * @date 2020-05-11 16:05:03
     */
    public static LocalDate dateToLocalDate(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * Date对象转LocalDateTime对象
     *
     * @param date
     * @return java.time.LocalDateTime
     * @author 徐延
     * @date 2020-05-11 16:04:41
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * LocalDate对象转Date对象
     *
     * @param localDate
     * @return java.time.LocalDate
     * @author 徐延
     * @date 2020-05-11 16:05:03
     */
    public static Date localDateToDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    /**
     * LocalDateTime对象转Date对象
     *
     * @param localDateTime
     * @return java.time.LocalDateTime
     * @author 徐延
     * @date 2020-05-11 16:04:41
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 字符串转Date
     *
     * @param str
     * @param pattern
     * @return java.util.Date
     * @author 徐延
     * @date 2019-10-23 15:16:26
     */
    public static Date parseDate(String str, String pattern) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
        if (pattern.contains("HH") || pattern.contains("mm") || pattern.contains("ss")) {
            return localDateTimeToDate(LocalDateTime.parse(str, df));
        }
        return localDateToDate(LocalDate.parse(str, df));
    }

    /**
     * Date转字符串
     *
     * @param date
     * @param pattern
     * @return java.lang.String
     * @author 徐延
     * @date 2019-10-23 15:16:29
     */
    public static String format(Date date, String pattern) {
        LocalDateTime localDateTime = dateToLocalDateTime(date);
        DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
        return localDateTime.format(df);
    }

    /**
     * 获取指定格式化的日期
     *
     * @param date
     * @param pattern yyyy-MM-dd HH:mm:ss
     * @return java.util.Date
     * @author 徐延
     * @date 2019-04-13 10:42:33
     */
    public static Date formatToDate(Date date, String pattern) {
        return parseDate(format(date, pattern), "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 获取周第一天
     *
     * @param date
     * @return java.util.Date
     * @author 徐延
     * @date 2019-04-13 10:38:59
     */
    public static Date getStartDayOfWeek(Date date) {
        LocalDate localDate = dateToLocalDate(date);
        TemporalField fieldIso = WeekFields.ISO.dayOfWeek();
        localDate = localDate.with(fieldIso, 1);
        return localDateToDate(localDate);
    }

    /**
     * 获取周最后一天
     *
     * @param date
     * @return java.util.Date
     * @author 徐延
     * @date 2019-04-13 10:34:38
     */
    public static Date getEndDayOfWeek(Date date) {
        LocalDate localDate = dateToLocalDate(date);
        TemporalField fieldIso = WeekFields.ISO.dayOfWeek();
        localDate = localDate.with(fieldIso, 7);
        return Date.from(
                localDate
                        .atStartOfDay(ZoneId.systemDefault())
                        .plusDays(1L)
                        .minusNanos(1L)
                        .toInstant());
    }

    /**
     * 获取月第一天
     *
     * @param date
     * @return java.util.Date
     * @author 徐延
     * @date 2019-04-13 10:34:38
     */
    public static Date getStartDayOfMonth(Date date) {
        LocalDate localDate = dateToLocalDate(date);
        localDate = localDate.with(TemporalAdjusters.firstDayOfMonth());
        return localDateToDate(localDate);
    }

    /**
     * 获取月最后一天
     *
     * @param date
     * @return java.util.Date
     * @author 徐延
     * @date 2019-04-13 10:34:38
     */
    public static Date getEndDayOfMonth(Date date) {
        LocalDate localDate = dateToLocalDate(date);
        localDate = localDate.with(TemporalAdjusters.lastDayOfMonth());
        return Date.from(
                localDate
                        .atStartOfDay(ZoneId.systemDefault())
                        .plusDays(1L)
                        .minusNanos(1L)
                        .toInstant());
    }

    /**
     * 日期加
     *
     * @param date
     * @param amountToAdd
     * @param unit ChronoUnit.DAYS
     * @return java.util.Date
     * @author 徐延
     * @date 2019-04-15 17:46:16
     */
    public static Date add(Date date, long amountToAdd, TemporalUnit unit) {
        LocalDateTime localDateTime = dateToLocalDateTime(date);
        LocalDateTime newLocalDateTime = localDateTime.plus(amountToAdd, unit);
        return localDateTimeToDate(newLocalDateTime);
    }

    /**
     * 日期减
     *
     * @param date
     * @param amountTosubtract
     * @param unit ChronoUnit.DAYS
     * @return java.util.Date
     * @author 徐延
     * @date 2019-04-15 17:46:16
     */
    public static Date subtract(Date date, long amountTosubtract, TemporalUnit unit) {
        LocalDateTime localDateTime = dateToLocalDateTime(date);
        LocalDateTime newLocalDateTime = localDateTime.minus(amountTosubtract, unit);
        return localDateTimeToDate(newLocalDateTime);
    }

    /**
     * 转换时区,
     *
     * <p>注意: 仅是把值按时区改变, date里的实际时区还是之前的
     *
     * @param date
     * @param oldZone
     * @param newZone
     * @return java.util.Date
     * @author 徐延
     * @date 2019-06-06 14:40:42
     */
    public static Date changeTimeZone(Date date, TimeZone oldZone, TimeZone newZone) {
        int timeOffset = oldZone.getRawOffset() - newZone.getRawOffset();
        return new Date(date.getTime() - timeOffset);
    }

    /**
     * 转换为UTC时区,
     *
     * <p>注意: 仅是把值按时区改变, date里的实际时区还是之前的
     *
     * @param date
     * @return java.util.Date
     * @author 徐延
     * @date 2019-06-06 14:45:02
     */
    public static Date toUtcTimeZone(Date date) {
        return changeTimeZone(date, TimeZone.getDefault(), TimeZone.getTimeZone("UTC"));
    }

    /**
     * utc时间转为默认时区时间
     *
     * <p>注意: 仅是把值按时区改变, date里的实际时区还是之前的
     *
     * @param date
     * @return java.util.Date
     * @author 徐延
     * @date 2019-06-13 17:34:10
     */
    public static Date utcToDefaultTimeZone(Date date) {
        return changeTimeZone(date, TimeZone.getTimeZone("UTC"), TimeZone.getDefault());
    }

    /**
     * 获取加减时间用的时间间隔
     *
     * @param name
     * @return java.time.temporal.TemporalUnit
     * @author 徐延
     * @date 2020-03-05 19:22:26
     */
    public static TemporalUnit getChronoUnit(String name) {
        TemporalUnit temporalUnit;
        switch (name) {
            case "seconds":
                temporalUnit = ChronoUnit.SECONDS;
                break;
            case "minutes":
                temporalUnit = ChronoUnit.MINUTES;
                break;
            case "hours":
                temporalUnit = ChronoUnit.HOURS;
                break;
            case "days":
                temporalUnit = ChronoUnit.DAYS;
                break;
            case "weeks":
                temporalUnit = ChronoUnit.WEEKS;
                break;
            case "months":
                temporalUnit = ChronoUnit.MONTHS;
                break;
            case "years":
                temporalUnit = ChronoUnit.YEARS;
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + name);
        }
        return temporalUnit;
    }

    /**
     * 获取指定格式时间
     *
     * @param localDateTime
     * @param fmt
     * @return
     */
    public static String localDateTimeToString(LocalDateTime localDateTime, String fmt) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(fmt);
        return localDateTime.format(formatter);
    }

    /**
     * 根据时间字符串获取日期时间对象
     *
     * @param timeStr
     * @param fmt
     * @return
     */
    public static LocalDateTime stringToLocalDateTime(String timeStr, String fmt) {
        Date date = parseDate(timeStr, fmt);
        return dateToLocalDateTime(date);
    }

    /**
     * 判断当前时间是否在[startTime, endTime]区间，注意时间格式要⼀致
     *
     * @param nowTime 当前时间
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return
     * @author jqlin
     */
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime.getTime() == startTime.getTime() || nowTime.getTime() == endTime.getTime()) {
            return true;
        }
        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);
        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);
        Calendar end = Calendar.getInstance();
        end.setTime(endTime);
        if (date.after(begin) && date.before(end)) {
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) {
        Date now = new Date();
        System.out.println(formatToDate(now, "yyyy-MM-dd 11:12:13"));
        System.out.println(getStartDayOfWeek(now));
        System.out.println(getEndDayOfWeek(now));
        System.out.println(getStartDayOfMonth(now));
        System.out.println(getEndDayOfMonth(now));
        System.out.println(add(now, 1, ChronoUnit.DAYS));
        System.out.println(subtract(now, 1, ChronoUnit.HOURS));
        System.out.println(parseDate("2019-05-14", "yyyy-MM-dd"));
        System.out.println(toUtcTimeZone(new Date()));
    }

    public static LocalDateTime getLocalDateTimeHour() {
        LocalDate localDate = LocalDate.now();
        return LocalDateTime.of(
                localDate.getYear(),
                localDate.getMonthValue(),
                localDate.getDayOfMonth(),
                LocalTime.now().getHour(),
                0);
    }

    /**
     * 日期(时间)转化为字符串.
     *
     * @param formater 日期或时间的格式.
     * @param aDate java.util.Date类的实例.
     * @return 日期转化后的字符串.
     */
    public static String date2String(String formater, Date aDate) {
        if (formater == null || "".equals(formater)) {
            return null;
        }
        if (aDate == null) {
            return null;
        }
        return (new SimpleDateFormat(formater)).format(aDate);
    }

    public static Date calculateByHour(Date d, int amount) {
        return calculate(d, GregorianCalendar.HOUR, amount);
    }

    public static Date calculate(Date d, int field, int amount) {
        if (d == null) {
            return null;
        }
        GregorianCalendar g = new GregorianCalendar();
        // g.setGregorianChange(d);
        g.setTime(d);
        g.add(field, amount);
        return g.getTime();
    }

    /**
     * 当前日期(时间)转化为字符串.
     *
     * @param formater 日期或时间的格式.
     * @return 日期转化后的字符串.
     */
    public static String date2String(String formater) {
        return date2String(formater, new Date());
    }

    public static LocalDateTime milliToLocalDateTime(Long milli) {
        return LocalDateTime.ofEpochSecond(milli / 1000, 0, ZoneOffset.ofHours(8));
    }

    public static LocalDate stringToLocalDate(String dateStr, String format) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(format);
        return LocalDate.parse(dateStr, fmt);
    }

    public static LocalDate stringToLocalDate(String dateStr) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(WEB_FORMATOR_ym);
        return LocalDate.parse(dateStr, fmt);
    }

    public static LocalTime stringToLocalTime(String dateStr) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(WEB_FORMATOR_HM);
        return LocalTime.parse(dateStr, fmt);
    }

    public static LocalTime stringToLocalTime(String dateStr, String format) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(format);
        return LocalTime.parse(dateStr, fmt);
    }

    public static LocalDateTime getRound10MinuteTime() {
        LocalDateTime localDateTime = LocalDateTime.now();
        int minute = localDateTime.getMinute();
        minute = (minute / 10) * 10;
        return localDateTime.withMinute(minute).withSecond(0).withNano(0);
    }

    public static Calendar getCalendar(String calendarStr) {
        Date date = parseDate(calendarStr, DATEFORMART_DEFAULT2);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * 根据格式转换
     *
     * @param date_Str 时间串
     * @param formate 时间格式
     * @return date对象
     */
    public static Date str2DateByFormat(String date_Str, String formate) {
        Date date = null;
        try {
            DateFormat FORMAT_TIME = new SimpleDateFormat(formate);
            date = FORMAT_TIME.parse(date_Str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return date;
    }

    public static Date calculateByDate(Date d, int amount) {
        return calculate(d, GregorianCalendar.DATE, amount);
    }

    public static String calculateByMinute(String d, int amount, String format) {
        Date date = str2DateBylength(d);
        date = calculate(date, GregorianCalendar.MINUTE, amount);
        return date2String(format, date);
    }

    public static DateFormat FORMAT_TIME = null;

    public static Date str2DateBylength(String date_Str) {
        String dateStr = date_Str;
        if (date_Str == null || date_Str.trim().length() == 0) {
            return new Date();
        }
        int len = dateStr.length();
        try {
            if (len >= 19) {
                dateStr = dateStr.substring(0, 19);
                FORMAT_TIME = new SimpleDateFormat(DATEFORMART_DEFAULT);
            } else if (len >= 14) {
                dateStr = dateStr.substring(0, 14);
                FORMAT_TIME = new SimpleDateFormat(DATEFORMART_HMS);
            } else if (len >= 12) {
                dateStr = dateStr.substring(0, 12);
                FORMAT_TIME = new SimpleDateFormat(DATEFORMART_HM);
            } else if (len >= 10) {
                dateStr = dateStr.substring(0, 10);
                FORMAT_TIME = new SimpleDateFormat(DATEFORMART_YMDH);
            } else if (len >= 8) {
                dateStr = dateStr.substring(0, 8);
                FORMAT_TIME = new SimpleDateFormat(DATEFORMAT_YMD);
            } else {
                return new Date();
            }
            return FORMAT_TIME.parse(dateStr);
        } catch (Exception e) {
            e.printStackTrace();
            return new Date();
        }
    }

    /**
     * 时间字符串转换为时间格式
     *
     * @param date 日期
     * @param format 总体安排
     * @return {@link Timestamp}
     */
    public static Timestamp formatStringToTimestamp(Object date, String format) {
        if (date == null) {
            return null;
        }
        Date nDate = str2DateByFormat(date.toString(), format);
        if (nDate == null) {
            return null;
        }
        return new Timestamp(nDate.getTime());
    }
}
